package com.ruoyi.framework.login.api;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.ruoyi.common.enums.RRExceptionCodeEnum;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * ThirdSession拦截器
 * 校验每个请求的ThirdSession
 *
 * @author byChen
 */
@Component
public class ApiSessionInterceptor implements HandlerInterceptor {

    /**
     * 判断接口是否添加了需要携带session的注解 @MiniLogin
     * 以及请求是否携带sessionKey,并且判断session是否过期
     *
     * @param request  Request
     * @param response Response
     * @param handler  handler
     * @return 是否通行
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断静态资源放行
        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            //判断访问的control是否添加ApiLogin注解
            if (method.hasMethodAnnotation(ApiLoginOpen.class)) {
                // 添加open接口得放开访问
                return Boolean.TRUE;
            }

            String requestURI = request.getRequestURI();

            Map<String, ApiSessionKeyFilter> apiSessionKeyFilterBeanByNameMap
                    = SpringUtil.getBeansOfType(ApiSessionKeyFilter.class);

            for (Map.Entry<String, ApiSessionKeyFilter> apiSessionKeyFilterEntry : apiSessionKeyFilterBeanByNameMap.entrySet()) {
                ApiSessionKeyFilter filter = apiSessionKeyFilterEntry.getValue();
                // 匹配白名单前缀 放行
                if (filter.urlWhiteList().stream().anyMatch(url -> StrUtil.startWith(requestURI, url))) {
                    return true;
                }
                if (requestURI.startsWith(filter.getUrlPrefix())) {
                    return filter.filter(request, response);
                }
            }
            throw new ServiceException(RRExceptionCodeEnum.API_HAVE_NO_SESSION.getMessage(), RRExceptionCodeEnum.API_HAVE_NO_SESSION.getCode());
        } else {
            return Boolean.TRUE;
        }
    }
}
